﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using DevExpress.XtraRichEdit.Model.History;
using DevExpress.XtraSplashScreen;

namespace TDesktop
{
    #region 委托类型

    /// <summary>
    /// 表示插件加载事件 PluginLoading 使用的委托类型。
    /// </summary>
    /// <param name="sender">事件源</param>
    /// <param name="e">包含事件数据的 PluginLoadingEventArgs</param>
    public delegate void PluginLoadingEventHandler(Object sender, PluginLoadingEventArgs e);

    /// <summary>
    /// 表示插件加载事件 PluginLoaded 使用的委托类型。
    /// </summary>
    /// <param name="sender">事件源</param>
    /// <param name="e">包含事件数据的 PluginLoadedEventArgs</param>
    public delegate void PluginLoadedEventHandler(Object sender, PluginLoadedEventArgs e);

    /// <summary>
    /// 表示插件卸载事件 PluginUnloading 使用的委托类型。
    /// </summary>
    /// <param name="sender">事件源</param>
    /// <param name="e">包含事件数据的 PluginUnloadingEventArgs</param>
    public delegate void PluginUnLoadingEventHandler(Object sender, PluginUnloadingEventArgs e);

    /// <summary>
    /// 表示插件卸载事件 PluginUnloaded 使用的委托类型。
    /// </summary>
    /// <param name="sender">事件源</param>
    /// <param name="e">包含事件数据的 PluginUnloadedEventArgs</param>
    public delegate void PluginUnLoadedEventHandler(Object sender, PluginUnloadedEventArgs e);

    /// <summary>
    /// 为 PluginLoading 事件提供数据。
    /// </summary>
    public class PluginLoadingEventArgs : CancelEventArgs
    {
        /// <summary>
        /// 构造一个新的 PluginLoadingEventArgs 对象。
        /// </summary>
        public PluginLoadingEventArgs(IPlugin plugin)
        {
            m_plugin = plugin;
        }

        private IPlugin m_plugin;
        /// <summary>
        /// 获取即将加载的插件。 
        /// </summary>
        public IPlugin Plugin
        {
            get
            {
                return m_plugin;
            }
        }
    }

    /// <summary>
    /// 为 PluginLoaded 事件提供数据。
    /// </summary>
    public class PluginLoadedEventArgs : EventArgs
    {
        /// <summary>
        /// 构造一个新的 PluginLoadedEventArgs 对象。
        /// </summary>
        public PluginLoadedEventArgs(IPlugin[] plugin)
        {
            m_plugin = plugin;
        }

        private IPlugin[] m_plugin;
        /// <summary>
        /// 获取加载完成的插件。 
        /// </summary>
        public IPlugin[] Plugin
        {
            get
            {
                return m_plugin;
            }
        }
    }

    /// <summary>
    /// 为 PluginUnloading 事件提供数据。
    /// </summary>
    public class PluginUnloadingEventArgs : EventArgs
    {
        /// <summary>
        /// 构造一个新的 PluginUnloadingEventArgs 对象。
        /// </summary>
        public PluginUnloadingEventArgs()
        {
            m_cancel = false;
        }

        private Boolean m_cancel;
        /// <summary>
        /// 获取或设置一个值，指示是否取消操作。
        /// </summary>
        public Boolean Cancel
        {
            get
            {
                return m_cancel;
            }
            set
            {
                m_cancel = value;
            }
        }
    }

    /// <summary>
    /// 为 PluginUnloaded 事件提供数据。
    /// </summary>
    public class PluginUnloadedEventArgs : EventArgs
    {
        /// <summary>
        /// 构造一个新的 PluginUnloadedEventArgs 对象。
        /// </summary>
        public PluginUnloadedEventArgs(IPlugin plugin)
        {
            m_plugin = plugin;
        }

        private IPlugin m_plugin;
        /// <summary>
        /// 获取卸载完成的插件。 
        /// </summary>
        public IPlugin Plugin
        {
            get
            {
                return m_plugin;
            }
        }
    }

    #endregion

    internal class TPluginManager : IPluginManager
    {
        private List<IPlugin> m_plugins;

        #region 属性

        /// <summary>
        /// 插件集合
        /// </summary>
        public IPlugin[] Plugins
        {
            get => m_plugins.ToArray();
        }


        #endregion

        #region 构建函数

        /// <summary>
        /// 只允许在主框架使用构建函数
        /// </summary>
        internal TPluginManager()
        {
            m_plugins = new List<IPlugin>();
        }

        #endregion

        #region 调用加载插件

        /// <summary>
        /// 判断DLL中是否继承了Iplugin接口
        /// </summary> <param name="t"></param>
        /// <returns></returns>
        private bool IsValidPlugin(Type t)
        {
            bool ret = false;
            Type[] interfaces = t.GetInterfaces();
            foreach (Type @Interface in interfaces)
            {
                if (@Interface.FullName == "TDesktop.IPlugin")
                {
                    ret = true;
                    break;
                }
            }
            return ret;
        }

        /// <summary>
        /// 读取所有插件
        /// </summary>
        internal IPlugin[] Load()
        {
            //string[] files = Directory.GetFiles(Tag.PluginDirPath);
            string[] files = GetAllFiles(Tag.PluginDirPath);
            int i = 0;

            foreach (string file in files)
            {
                string ext = Path.GetExtension(file);
                if (ext != ".dll") continue;
                try
                {
                    //为了能实时卸载插件，这里用数据流读取文件内容，这样就不会封锁文件
                    byte[] fileData = File.ReadAllBytes(file);
                    Assembly tmp;
                    Type[] types;
                    //Assembly tmp = Assembly.LoadFile(file);
                    //防止报错
                    try
                    {
                        tmp = Assembly.Load(fileData);
                        types = tmp.GetTypes();


                        bool ok = false;
                        foreach (Type t in types)
                        {
                            if (IsValidPlugin(t))
                            {
                                IPlugin plugin = (IPlugin)tmp.CreateInstance(t.FullName);
                                TPluginInfo info = new TPluginInfo()
                                {
                                    FilePath = file,
                                    Name = Path.GetFileName(file),
                                    Version = FileVersionInfo.GetVersionInfo(file).ProductVersion
                                };
                                (plugin as TPlugin).GetPluginInfo(info);

                                //添加加载中事件
                                PluginLoadingEventArgs args = new PluginLoadingEventArgs(plugin);
                                if (PluginLoading != null)
                                {
                                    PluginLoading(this, args);
                                }
                                if (args.Cancel) continue;
                                //添加完毕

                                m_plugins.Add(plugin);
                                ok = true;
                                if (ok) break;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        continue;
                    }
                    //添加加载后事件
                    PluginLoadedEventArgs loadedArgs = new PluginLoadedEventArgs(m_plugins.ToArray());
                    if (PluginLoaded != null)
                    {
                        PluginLoaded(this, loadedArgs);
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
            }

            return m_plugins.ToArray();
        }

        private string[] GetAllFiles(string path)
        {
            List<string> list = new List<string>();
            list.AddRange(Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories));

            //string[] dirs = Directory.GetDirectories(path);
            //foreach (string dir in dirs)
            //{
            //    list.AddRange(GetAllFiles(dir));
            //}
            return list.ToArray();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 移除插件
        /// </summary>
        /// <param name="plugin"></param>
        /// <returns></returns>
        public Boolean Remove(IPlugin plugin)
        {
            if (m_plugins.Contains(plugin))
            {
                m_plugins.Remove(plugin);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 添加插件的时候
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public IPlugin AddPlugin(string filePath)
        {
            IPlugin plugin = null;
            string ext = Path.GetExtension(filePath);
            if (ext != ".dll") return null;
            try
            {
                //为了能实时卸载插件，这里用数据流读取文件内容，这样就不会封锁文件
                byte[] fileData = File.ReadAllBytes(filePath);
                Assembly tmp = Assembly.Load(fileData);
                //Assembly tmp = Assembly.LoadFile(file);
                Type[] types = tmp.GetTypes();
                bool ok = false;
                foreach (Type t in types)
                    if (IsValidPlugin(t))
                    {
                        plugin = (IPlugin)tmp.CreateInstance(t.FullName);
                        TPluginInfo info = new TPluginInfo()
                        {
                            FilePath = filePath,
                            Name = Path.GetFileName(filePath),
                            Version = FileVersionInfo.GetVersionInfo(filePath).FileVersion
                        };
                        (plugin as TPlugin).GetPluginInfo(info);

                        //添加加载中事件
                        PluginLoadingEventArgs args = new PluginLoadingEventArgs(plugin);
                        if (PluginLoading != null)
                        {
                            PluginLoading(this, args);
                        }
                        if (args.Cancel) continue;
                        //添加完毕

                        m_plugins.Add(plugin);
                        (Application.ActiveApplication.MainForm as MainFrm).AddDockPanel(new IPlugin[] { plugin });

                        ok = true;
                        if (ok) break;
                    }
            }
            catch (Exception e)
            {
                throw e;
            }
            //添加加载后事件
            PluginLoadedEventArgs loadedArgs = new PluginLoadedEventArgs(m_plugins.ToArray());
            if (PluginLoaded != null)
            {
                PluginLoaded(this, loadedArgs);
            }
            return plugin;
        }

        /// <summary>
        /// 添加多个插件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public IPlugin[] AddPlugins(string[] filePath)
        {
            List<IPlugin> list = new List<IPlugin>();
            foreach (string file in filePath)
            {
                list.Add(AddPlugin(file));
            }
            return list.ToArray();
        }

        #endregion


        #region 委托

        /// <summary>
        /// 插件加载前将触发该事件。
        /// </summary>
        public event PluginLoadingEventHandler PluginLoading;

        /// <summary>
        /// 插件加载完毕时将触发该事件。
        /// </summary>
        public event PluginLoadedEventHandler PluginLoaded;

        /// <summary>
        /// 插件卸载前将触发该事件。
        /// </summary>
        [Obsolete("没有实现", false)]
        public event PluginUnLoadingEventHandler PluginUnloading;

        /// <summary>
        /// 插件卸载完毕时将触发该事件。
        /// </summary>
        [Obsolete("没有实现", false)]
        public event PluginUnLoadedEventHandler PluginUnloaded;

        #endregion
    }
}
